package com.fsh.subject.infra.basic.es;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.http.HttpHost;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.*;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;

/**
 * 作者：fsh
 * 日期：2023/12/23
 * <p>
 * 描述：ES  客户端 , 封装着我们自定义的 CURD 操作
 */
@Component
@Slf4j
public class EsRestClient {
    // 声明一个名为clientMap的静态Map，键为String类型，值为RestHighLevelClient类型。
    // 这是一个用于存储Elasticsearch客户端的映射。
    public static Map<String, RestHighLevelClient> clientMap = new HashMap<>();

    // 使用@Resource注解自动注入EsConfigProperties类型的esConfigProperties。
    // 这个属性可能包含了Elasticsearch的相关配置。
    @Resource
    private EsConfigProperties esConfigProperties;

    /**
     * 这个方法目的就是 根据配置文件中的es节点信息创建 Elasticsearch客户端。
     * 创建的客户端存在 clientMap中 ，key为节点的name ，value为es客户端对象
     * # es节点信息 ，通过es-head查看
     * es:
     *   cluster:
     *     esConfigs[0]:
     *       name: 791bb269e4be
     *       nodes: 192.168.133.135:9200
     *     #示例两个节点
     *     esConfigs[1]:
     *       name: aaaaa4545
     *       nodes: 111.222.333.444:6666,192.166.135.456:5652
     *
     */// 使用@PostConstruct注解标记的initialize方法会在依赖注入完成后自动执行。
    @PostConstruct
    public void initialize() {
        // 从esConfigProperties中获取Elasticsearch的配置列表。
        List<EsClusterConfig> esConfigs = esConfigProperties.getEsConfigs();
        // 遍历每个Elasticsearch配置。
        for (EsClusterConfig esConfig : esConfigs) {
            // 打印当前配置的名称和节点信息。
            log.info("initialize.config.name:{},node:{}", esConfig.getName(), esConfig.getNodes());
            // 初始化RestHighLevelClient客户端。
            RestHighLevelClient restHighLevelClient = initRestClient(esConfig);
            // 如果客户端初始化成功（不为null）。
            if (restHighLevelClient != null) {
                // 将客户端添加到clientMap中，键为esConfig的名称。
                clientMap.put(esConfig.getName(), restHighLevelClient);
            } else {
                // 如果客户端初始化失败，打印错误信息。
                log.error("config.name:{},node:{}.initError", esConfig.getName(), esConfig.getNodes());
            }
        }
    }


    /**
     * 私有方法，用于根据给定的EsClusterConfig对象信息初始化RestHighLevelClient客户端。
     */
    private RestHighLevelClient initRestClient(EsClusterConfig esClusterConfig) {
        // 从esClusterConfig中获取节点信息，并使用逗号进行分割。(因为一个集群可能有两个节点，所以要逗号分隔)
        String[] ipPortArr = esClusterConfig.getNodes().split(",");
        // 创建一个ArrayList来存储HttpHost对象。
        List<HttpHost> httpHostList = new ArrayList<>(ipPortArr.length);
        // 遍历每个ipPort。
        for (String ipPort : ipPortArr) {
            // 使用冒号进行分割，获取IP和端口信息。
            String[] ipPortInfo = ipPort.split(":");
            // 如果分割成功，并且长度为2（IP和端口）。
            if (ipPortInfo.length == 2) {
                // 创建一个新的HttpHost对象，并使用IP和端口信息进行初始化。
                HttpHost httpHost = new HttpHost(ipPortInfo[0], NumberUtils.toInt(ipPortInfo[1]));
                // 将httpHost添加到httpHostList中。
                httpHostList.add(httpHost);
            }
        }
        // 将httpHostList中的元素转换为数组。
        HttpHost[] httpHosts = new HttpHost[httpHostList.size()];
        httpHostList.toArray(httpHosts);

        // 创建一个RestClientBuilder，并将httpHosts作为参数传入。
        RestClientBuilder builder = RestClient.builder(httpHosts);
        // 使用builder创建一个新的RestHighLevelClient客户端。
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
        // 返回创建的客户端。
        return restHighLevelClient;
    }


    //------------------以下就是CURD操作-----------------------------

    // 声明一个私有的静态变量COMMON_OPTIONS，它可能被用作通用的请求选项。
    private static final RequestOptions COMMON_OPTIONS;

    // 静态代码块，用于初始化COMMON_OPTIONS。
    // 首先，通过RequestOptions.DEFAULT.toBuilder()创建一个RequestOptions的构建器，
    // 然后使用该构建器构建并初始化COMMON_OPTIONS。
    static {
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        COMMON_OPTIONS = builder.build();
    }

    /**
     * 定义一个私有静态方法，根据传入的集群名称clusterName获取对应的RestHighLevelClient客户端。
     */
    private static RestHighLevelClient getClient(String clusterName){
        return clientMap.get(clusterName);
    }

    /**
     * @param esIndexInfo  ES 索引信息
     * @param esSourceData ES 源数据
     *
     * 定义一个公共静态方法，用于向Elasticsearch中插入文档。
     */
    public static boolean insertDoc(EsIndexInfo esIndexInfo, EsSourceData esSourceData) {
        try {
            // 创建一个IndexRequest对象，指定要插入数据的索引名称。
            IndexRequest indexRequest = new IndexRequest(esIndexInfo.getIndexName());
            // 设置要插入的数据。
            indexRequest.source(esSourceData.getData());
            // 设置文档的ID。
            indexRequest.id(esSourceData.getDocId());
            // 获取对应的Elasticsearch客户端，并使用该客户端将数据插入到指定的索引中。
            getClient(esIndexInfo.getClusterName()).index(indexRequest, COMMON_OPTIONS);
            // 如果成功插入，返回true。
            return true;
        } catch (Exception e) {
            // 如果出现异常，记录错误日志。
            log.error("insertDoc.exception:{}", e.getMessage(), e);
        }
        // 如果出现异常，返回false。
        return false;
    }

    /**
     * @param esIndexInfo      ES 索引信息
     * @param esSourceDataList ES 源数据列表
     * @return boolean
     *
     * 定义一个公共静态方法，用于向Elasticsearch中批量插入文档。
     */
    public static boolean batchInsertDoc(EsIndexInfo esIndexInfo, List<EsSourceData> esSourceDataList) {
        // 判断日志级别是否为INFO，如果是，则记录批量插入ES的日志
        if (log.isInfoEnabled()) {
            log.info("批量新增ES:" + esSourceDataList.size());
            log.info("indexName:" + esIndexInfo.getIndexName());
        }
        try {
            // 初始化一个布尔变量flag，用于标记是否有数据插入成功
            boolean flag = false;
            // 创建一个批量请求对象
            BulkRequest bulkRequest = new BulkRequest();

            // 遍历esSourceDataList列表中的每个EsSourceData对象
            for (EsSourceData source : esSourceDataList) {
                // 获取当前EsSourceData对象的docId
                String docId = source.getDocId();
                // 如果docId不为空，则进行后续操作
                if (StringUtils.isNotBlank(docId)) {
                    // 创建一个索引请求对象，指定索引名称
                    IndexRequest indexRequest = new IndexRequest(esIndexInfo.getIndexName());
                    // 设置索引请求的ID为docId
                    indexRequest.id(docId);
                    // 设置索引请求的数据为当前EsSourceData对象的数据
                    indexRequest.source(source.getData());
                    // 将索引请求添加到批量请求中
                    bulkRequest.add(indexRequest);
                    // 将flag设置为true，表示有数据插入成功
                    flag = true;
                }
            }

            // 如果flag为true，则执行批量插入操作
            if (flag) {
                // 执行批量插入操作，并将返回的响应保存在response中
                BulkResponse response = getClient(esIndexInfo.getClusterName()).bulk(bulkRequest, COMMON_OPTIONS);
                // 如果批量插入操作有失败的情况，则返回false，表示批量插入失败
                if (response.hasFailures()) {
                    return false;
                }
            }
        } catch (Exception e) {
            // 如果在执行过程中出现异常，记录错误日志
            log.error("batchInsertDoc.error", e);
        }
        // 无论成功还是失败，都返回true，表示批量插入操作已完成
        return true;
    }


    /**
     * @param esIndexInfo  ES 索引信息
     * @param esSourceData ES 源数据
     *
     * 定义一个公共静态方法，用于更新Elasticsearch中的文档。 全量更新
     */
    public static boolean updateDoc(EsIndexInfo esIndexInfo, EsSourceData esSourceData) {
        try {
            // 创建一个UpdateRequest对象。
            UpdateRequest updateRequest = new UpdateRequest();
            // 设置要更新的索引名称。
            updateRequest.index(esIndexInfo.getIndexName());
            // 设置要更新的文档的ID。
            updateRequest.id(esSourceData.getDocId());
            // 设置要更新的数据。
            updateRequest.doc(esSourceData.getData());
            // 获取对应的Elasticsearch客户端，并使用该客户端更新指定的文档。
            getClient(esIndexInfo.getClusterName()).update(updateRequest, COMMON_OPTIONS);
            // 如果成功更新，返回true。
            return true;
        } catch (Exception e) {
            // 如果出现异常，记录错误日志。
            log.error("updateDoc.exception:{}", e.getMessage(), e);
        }
        // 如果出现异常，返回false。
        return false;
    }

    /**
     * @param esIndexInfo      ES 索引信息
     * @param esSourceDataList ES 源数据列表
     * @return boolean
     *
     * 定义一个公共静态方法，用于批量更新Elasticsearch中的文档。全量更新
     */
    public static boolean batchUpdateDoc(EsIndexInfo esIndexInfo,
                                         List<EsSourceData> esSourceDataList) {
        try {
            // 初始化一个标志变量，用于判断是否有文档需要更新。
            boolean flag = false;
            // 创建一个BulkRequest对象，用于批量执行更新操作。
            BulkRequest bulkRequest = new BulkRequest();
            // 遍历传入的文档数据列表。
            for (EsSourceData esSourceData : esSourceDataList) {
                // 获取当前文档的ID。
                String docId = esSourceData.getDocId();
                // 如果文档ID不为空或仅包含空白字符。
                if (StringUtils.isNotBlank(docId)) {
                    // 创建一个UpdateRequest对象，用于单个文档的更新。
                    UpdateRequest updateRequest = new UpdateRequest();
                    // 设置更新请求的目标索引名。
                    updateRequest.index(esIndexInfo.getIndexName());
                    // 设置更新请求的文档ID。
                    updateRequest.id(esSourceData.getDocId());
                    // 设置更新请求的文档内容。
                    updateRequest.doc(esSourceData.getData());
                    // 将更新请求添加到批量请求中。
                    bulkRequest.add(updateRequest);
                    // 设置标志变量为true，表示有文档需要更新。
                    flag = true;
                }
            }

            // 如果存在需要更新的文档。
            if (flag) {
                // 执行批量更新操作，并获取响应结果。
                BulkResponse bulk = getClient(esIndexInfo.getClusterName()).bulk(bulkRequest, COMMON_OPTIONS);
                // 如果更新操作有失败的情况。
                if (bulk.hasFailures()) {
                    // 返回false，表示批量更新操作失败。
                    return false;
                }
            }

            // 返回true，表示批量更新操作成功。
            return true;
        } catch (Exception e) {
            // 如果在执行过程中出现异常，记录错误日志。
            log.error("batchUpdateDoc.exception:{}", e.getMessage(), e);
        }
        // 如果出现异常，返回false。
        return false;
    }

    /**
     * @param esIndexInfo  ES 索引信息
     * @param queryBuilder 查询条件
     * @param script       更新脚本
     * @param batchSize    批量大小
     * @return boolean
     *
     * 增量更新
     * 它用于在Elasticsearch中执行基于查询的更新操作。
     */
    public static boolean updateByQuery(EsIndexInfo esIndexInfo, QueryBuilder queryBuilder, Script script, int batchSize) {
        // 检查日志级别是否为INFO，如果是，则记录updateByQuery操作的索引名称
        if (log.isInfoEnabled()) {
            log.info("updateByQuery.indexName:" + esIndexInfo.getIndexName());
        }
        try {
            // 创建一个UpdateByQueryRequest对象，设置其索引名称为esIndexInfo的indexName属性
            UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest(esIndexInfo.getIndexName());
            // 设置查询条件，使用QueryBuilder构建的查询条件
            updateByQueryRequest.setQuery(queryBuilder);
            // 设置更新脚本，用于更新文档内容
            updateByQueryRequest.setScript(script);
            // 设置批量大小
            updateByQueryRequest.setBatchSize(batchSize);
            // 设置当文档版本冲突时的行为，这里设置为不中断操作
            updateByQueryRequest.setAbortOnVersionConflict(false);
            // 执行updateByQuery操作，并获取响应结果
            BulkByScrollResponse response = getClient(esIndexInfo.getClusterName()).updateByQuery(updateByQueryRequest, RequestOptions.DEFAULT);
            // 获取响应中的批量操作失败列表
            List<BulkItemResponse.Failure> failures = response.getBulkFailures();
        } catch (Exception e) {
            // 如果在执行过程中出现异常，记录错误日志
            log.error("updateByQuery.error", e);
        }
        // 无论成功还是失败，都返回true，表示批量更新操作已完成
        return true;
    }


    /**
     * @param esIndexInfo ES 索引信息
     * @return boolean
     *
     * 定义一个公共静态方法，用于从Elasticsearch中删除文档。
     * 删除某个索引中的全部文档
     */
    public static boolean delete(EsIndexInfo esIndexInfo) {
        try {
            // 创建一个DeleteByQueryRequest对象，用于删除匹配查询条件的文档。
            DeleteByQueryRequest deleteByQueryRequest =
                    new DeleteByQueryRequest(esIndexInfo.getIndexName());
            // 设置查询条件，删除所有文档。
            deleteByQueryRequest.setQuery(QueryBuilders.matchAllQuery());
            // 获取Elasticsearch客户端。
            BulkByScrollResponse response = getClient(esIndexInfo.getClusterName())
                    .deleteByQuery(deleteByQueryRequest, COMMON_OPTIONS);
            // 获取被删除的文档数量。
            long deleted = response.getDeleted();
            // 记录日志，输出被删除的文档数量。
            log.info("deleted.size:{}", deleted);
            // 如果删除成功，返回true。
            return true;
        } catch (Exception e) {
            // 如果出现异常，记录错误日志。
            log.error("delete.exception:{}", e.getMessage(), e);
        }
        // 如果出现异常，返回false。
        return false;
    }

    /**
     * @param esIndexInfo ES 索引信息
     * @param docId       文档 ID
     * @return boolean
     * 定义一个公共静态方法，用于根据文档ID删除Elasticsearch中的文档。
     */
    public static boolean deleteDocById(EsIndexInfo esIndexInfo, String docId) {
        try {
            // 创建一个DeleteRequest对象，设置要删除的索引名和文档ID。
            DeleteRequest deleteRequest = new DeleteRequest(esIndexInfo.getIndexName());
            deleteRequest.id(docId);
            // 调用getClient方法获取Elasticsearch客户端，并执行删除操作。
            DeleteResponse response = getClient(esIndexInfo.getClusterName()).delete(deleteRequest, COMMON_OPTIONS);
            // 记录删除操作的响应信息。
            log.info("deleteDoc.response:{}", JSON.toJSONString(response));
            // 返回true，表示删除操作成功。
            return true;
        } catch (Exception e) {
            // 如果在执行过程中出现异常，记录错误日志。
            log.error("deleteDocById.exception:{}", e.getMessage(), e);
        }
        // 如果出现异常，返回false。
        return false;
    }


    /**
     * @param esIndexInfo ES 索引信息
     * @param docId       文档 ID
     * @return boolean
     *
     * 定义一个公共静态方法，用于检查Elasticsearch中是否存在指定ID的文档。
     */
    public static boolean isExistDocById(EsIndexInfo esIndexInfo, String docId) {
        try {
            // 创建一个GetRequest对象，设置要查询的索引名和文档ID。
            GetRequest getRequest = new GetRequest(esIndexInfo.getIndexName());
            getRequest.id(docId);
            // 调用getClient方法获取Elasticsearch客户端，并检查文档是否存在。
            return getClient(esIndexInfo.getClusterName()).exists(getRequest, COMMON_OPTIONS);
        } catch (Exception e) {
            // 如果在执行过程中出现异常，记录错误日志。注意这里的方法名写错了，应该是"isExistDocById"而不是"isExistDocByID"。
            log.error("isExistDocByID.exception:{}", e.getMessage(), e);
        }
        // 如果出现异常，返回false。
        return false;
    }


    /**
     * @param esIndexInfo ES 索引信息
     * @param docId       文档 ID
     *
     *  定义一个公共静态方法，用于根据文档ID获取Elasticsearch中的文档内容:
     *      是用于根据文档ID获取Elasticsearch中的文档内容。
     *      它只需要文档ID作为参数，通过这个ID直接从Elasticsearch中获取对应的文档内容。
     *      这个方法相对简单，适用于只需要获取整个文档内容的情况。
     */
    public static Map<String, Object> getDocById(EsIndexInfo esIndexInfo, String docId) {
        try {
            // 创建一个GetRequest对象，设置要查询的索引名和文档ID。
            GetRequest getRequest = new GetRequest(esIndexInfo.getIndexName());
            getRequest.id(docId);
            // 调用getClient方法获取Elasticsearch客户端，并获取文档内容。
            GetResponse response = getClient(esIndexInfo.getClusterName()).get(getRequest, COMMON_OPTIONS);
            // 从响应中提取文档内容。
            Map<String, Object> source = response.getSource();
            // 返回文档内容。
            return source;
        } catch (Exception e) {
            // 如果在执行过程中出现异常，记录错误日志。
            log.error("getDocById.exception:{}", e.getMessage(), e);
        }
        // 如果出现异常，返回null。
        return null;
    }

    /**
     * @param esIndexInfo ES 索引信息
     * @param docId       文档 ID
     * @param fields      字段
     * @return {@link Map }<{@link String }, {@link Object }>
     *
     * 定义一个公共静态方法，用于根据文档ID从Elasticsearch中获取文档：
     *      是用于根据文档ID从Elasticsearch中获取特定字段的文档内容。
     *      除了文档ID，它还接受一个字段数组作为参数，表示只获取这些字段的内容。
     *      通过FetchSourceContext，可以控制是否获取source、需要获取的字段以及是否限制其他字段。
     *      这个方法更加灵活，适用于只需要获取特定字段内容的情况。
     */
    public static Map<String, Object> getDocById(EsIndexInfo esIndexInfo, String docId,
                                                 String[] fields) {
        try {
            // 创建一个GetRequest对象，设置索引名称为esIndexInfo的indexName属性
            GetRequest getRequest = new GetRequest(esIndexInfo.getIndexName());
            // 设置要获取的文档ID
            getRequest.id(docId);
            // 创建一个FetchSourceContext对象，设置是否获取source为true，fields为要获取的字段数组，null表示不限制其他字段
            FetchSourceContext fetchSourceContext = new FetchSourceContext(true, fields, null);
            // 设置获取文档的source上下文
            getRequest.fetchSourceContext(fetchSourceContext);
            // 执行get请求，并获取响应结果
            GetResponse response = getClient(esIndexInfo.getClusterName()).get(getRequest, COMMON_OPTIONS);
            // 获取响应中的文档source内容，并转换为Map类型
            Map<String, Object> source = response.getSource();
            // 返回source内容
            return source;
        } catch (Exception e) {
            // 如果在执行过程中出现异常，记录错误日志，包含异常信息及堆栈轨迹
            log.error("getDocById.exception:{}", e.getMessage(), e);
        }
        // 如果出现异常，返回null
        return null;
    }

    /**
     * @param esIndexInfo     ES 索引信息
     * @param esSearchRequest ES 搜索请求
     * @return {@link SearchResponse }
     *
     * 定义一个公共静态方法，用于使用词项查询进行搜索。
     */
    public static SearchResponse searchWithTermQuery(EsIndexInfo esIndexInfo
            , EsSearchRequest esSearchRequest) {
        try {
            // 获取Bool查询构建器、字段数组、起始位置、返回结果数量、滚动时间、是否需要滚动以及排序名称和排序顺序。
            BoolQueryBuilder bq = esSearchRequest.getBq();
            String[] fields = esSearchRequest.getFields();
            int from = esSearchRequest.getFrom();
            int size = esSearchRequest.getSize();
            Long minutes = esSearchRequest.getMinutes();
            Boolean needScroll = esSearchRequest.getNeedScroll();
            String sortName = esSearchRequest.getSortName();
            SortOrder sortOrder = esSearchRequest.getSortOrder();

            // 创建一个新的SearchSourceBuilder对象，用于构建搜索请求的源。
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            // 将Bool查询构建器添加到搜索源中。
            searchSourceBuilder.query(bq);
            // 设置要检索的字段和结果返回数量。
            searchSourceBuilder.fetchSource(fields, null).from(from).size(size);

            // 如果HighlightBuilder不为空，则将其添加到搜索源中，以启用高亮显示功能。
            if (Objects.nonNull(esSearchRequest.getHighlightBuilder())) {
                searchSourceBuilder.highlighter(esSearchRequest.getHighlightBuilder());
            }

            // 如果排序名称不为空，则按照该名称进行排序。
            if (StringUtils.isNotBlank(sortName)) {
                searchSourceBuilder.sort(sortName);
            }

            // 按照得分进行降序排序。
            searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));

            // 创建一个新的SearchRequest对象，设置搜索类型、索引名称和搜索源。
            SearchRequest searchRequest = new SearchRequest();
            searchRequest.searchType(SearchType.DEFAULT);
            searchRequest.indices(esIndexInfo.getIndexName());
            searchRequest.source(searchSourceBuilder);
            // 如果需要滚动，则设置滚动时间并启用滚动功能。
            if (needScroll) {
                Scroll scroll = new Scroll(TimeValue.timeValueMinutes(minutes));
                searchRequest.scroll(scroll);
            }
            // 执行搜索请求并获取响应。
            SearchResponse search = getClient(esIndexInfo.getClusterName()).search(searchRequest, COMMON_OPTIONS);
            return search;  // 返回搜索响应。
        } catch (Exception e) {
            // 如果在执行过程中出现异常，记录错误日志。
            log.error("searchWithTermQuery.exception:{}", e.getMessage(), e);
        }
        return null;  // 如果出现异常，返回null。
    }


    /**
     * 分词方法
     */
    public static List<String> getAnalyze(EsIndexInfo esIndexInfo, String text) throws Exception {
        // 创建一个ArrayList对象用于存储分词结果
        List<String> list = new ArrayList<String>();
        // 创建一个Request对象，指定请求方法为GET，路径为"_analyze"（Elasticsearch的分析API）
        Request request = new Request("GET", "_analyze");
        // 创建一个JSONObject对象，用于构建请求实体内容
        JSONObject entity = new JSONObject();
        // 设置请求的分析器为"ik_smart"（一个中文分词器）
        entity.put("analyzer", "ik_smart");
        // 设置待分析的文本内容
        entity.put("text", text);
        // 将请求实体内容设置为JSON格式的字符串
        request.setJsonEntity(entity.toJSONString());
        // 执行请求并获取Response对象
        Response response = getClient(esIndexInfo.getClusterName()).getLowLevelClient().performRequest(request);
        // 将响应实体内容转换为JSONObject对象
        JSONObject tokens = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
        // 获取tokens中的tokens数组
        JSONArray arrays = tokens.getJSONArray("tokens");
        // 遍历tokens数组，获取每个token并添加到list中
        for (int i = 0; i < arrays.size(); i++) {
            JSONObject obj = JSON.parseObject(arrays.getString(i));
            list.add(obj.getString("token"));
        }
        // 返回分词结果列表
        return list;
    }

}
